#include <stdio.h>
#include <string>

class CData
{
public:
	bool Run(){
		printf( "%-5s 1\n", __FUNCTION__ );
		return true;
	};
	bool Run( int nParam ){
		printf( "%-5s 2, %d\n", __FUNCTION__, nParam );
		return true;
	}
	bool RunV( int nParam1, float fParam2 ){
		printf( "%-5s 3, %d, %f\n", __FUNCTION__, nParam1, fParam2 );
		return true;
	}
	bool RunP( int nParam, const char* pParam ){
		printf( "%-5s 4, %d, %s\n", __FUNCTION__, nParam, pParam );
		return true;
	}
	bool RunR( int nParam, const std::string& ref ){
		printf( "%-5s 5, %d, %s\n", __FUNCTION__, nParam, ref.c_str() );
		return true;
	}
};

class CCommandBase
{
	public:
		virtual ~CCommandBase() {}
		virtual void Execute( void *param ) = 0;
};

template <typename C, typename F, typename R>
class CFunCommand0 : public CCommandBase
{
	typedef R	result_type;
public:
	CFunCommand0( F func ) : m_func( func ) {}
	R Execute( C& c ){
		((&c)->*m_func)();
	};

	void Execute( void *param )
	{
		C* pClass = static_cast<C*>( param );
		(pClass->*m_func)();
	}
private:
	F		m_func;
};

template <typename C, typename F, typename R, typename P1>
class CFunCommand1 : public CCommandBase
{
public:
	CFunCommand1( F func, const P1& param1 ) :
		m_func( func ),
		m_param1( param1 )
	{}

	void Execute( void *param )
	{
		C* pClass = static_cast<C*>( param );
		(pClass->*m_func)( m_param1 );
	}
public:
	F		m_func;
	P1		m_param1;
};

template <typename C, typename F, typename R, typename P1, typename P2>
class CFunCommand2 : public CCommandBase
{
public:
	CFunCommand2( F func, const P1& param1, const P2& param2 ) :
		m_func( func ),
		m_param1( param1 ),
		m_param2( param2 )
	{}

	void Execute( void *param )
	{
		C* pClass = static_cast<C*>( param );
		(pClass->*m_func)( m_param1, m_param2 );
	}
public:
	F		m_func;
	P1		m_param1;
	P2		m_param2;
};

template <typename C, typename F, typename R, typename P1, typename P2>
class CFunCommand2<C, F, R, P1, P2*> : public CCommandBase
{
public:
	CFunCommand2( F func, const P1& param1, const P2* param2 ) :
		m_func( func ),
		m_param1( param1 ),
		m_param2( param2 )
	{
	}

	void Execute( void *param )
	{
		C* pClass = static_cast<C*>( param );
		(pClass->*m_func)( m_param1, m_param2 );
	}
public:
	F		m_func;
	P1		m_param1;
	P2*		m_param2;
};

template <typename C, typename R>
CCommandBase* FunCommandHelper( R (C::*func)() )
{
	typedef R (C::*F)();

	CCommandBase* pCommand = 
		new CFunCommand0<C, F, R>( func );
	return pCommand;
}

template <typename C, typename R, typename P1>
CCommandBase* FunCommandHelper( R (C::*func)(P1), const P1& param1 )
{
	typedef R (C::*F)(P1);
	CCommandBase* pCommand =
		new CFunCommand1<C, F, R, P1>( func, param1 );
	return pCommand;
}

template <typename C, typename R, typename P1, typename P2>
CCommandBase* FunCommandHelper( R (C::*func)(P1, P2), const P1& param1, const P2& param2 )
{
	typedef R (C::*F)(P1, P2);
	CCommandBase* pCommand =
		new CFunCommand2<C, F, R, P1, P2>( func, param1, param2 );
	return pCommand;
}

template <typename C, typename R, typename P1, typename P2>
CCommandBase* FunCommandHelper( R (C::*func)(P1, const P2&), const P1& param1, const P2& param2 )
{
	typedef R (C::*F)(P1, const P2&);
	CCommandBase* pCommand =
		new CFunCommand2<C, F, R, P1, P2>( func, param1, param2 );
	return pCommand;
}

template <typename C, typename R, typename P1, typename P2>
CCommandBase* FunCommandHelper( R (C::*func)(P1, P2*), const P1& param1, const P2* param2 )
{
	typedef R (C::*F)(P1, const P2*);
	CCommandBase* pCommand =
		new CFunCommand2<C, F, R, P1, P2*>( func, param1, param2 );
	return pCommand;
}

typedef void (CData::*F)();
typedef CFunCommand0< CData, F, void >	command_0_type;

int main( int argc, char* argv[] )
{
	CData	data;
	CCommandBase* pCommand = 0;
	pCommand = FunCommandHelper( &CData::Run );
	pCommand->Execute(&data);
	delete pCommand;

	pCommand = FunCommandHelper( &CData::Run, 1 );
	pCommand->Execute(&data);
	delete pCommand;

	pCommand = FunCommandHelper( &CData::RunV, 2, 2.0f );
	pCommand->Execute(&data);
	delete pCommand;

	const char* pBuff = "Test.";
	pCommand = FunCommandHelper( &CData::RunP, 2, pBuff );
	pCommand->Execute(&data);
	delete pCommand;

	std::string str(pBuff);
	pCommand = FunCommandHelper( &CData::RunR, 2, str );
	pCommand->Execute(&data);
	delete pCommand;

}

